Fix floating-point corruption (a nasty race in fp task-switch
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Sun, 30 Oct 2005 09:45:49 +0000 (10:45 +0100)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Sun, 30 Oct 2005 09:45:49 +0000 (10:45 +0100)
exception handling).
Signed-off-by: Keir Fraser <keir@xensource.com>
linux-2.6-xen-sparse/arch/xen/i386/kernel/entry.S
linux-2.6-xen-sparse/arch/xen/i386/kernel/traps.c
xen/arch/x86/traps.c

index 24c2d5a5fe850cd50d991479743c010f938a2f8e..d4ac275630d2e240858d1fe97bb281babf59dc42 100644 (file)
@@ -653,7 +653,7 @@ ENTRY(simd_coprocessor_error)
 ENTRY(device_not_available)
        pushl $-1                       # mark this as an int
        SAVE_ALL
-       preempt_stop
+       #preempt_stop /* This is already an interrupt gate on Xen. */
        call math_state_restore
        jmp ret_from_exception
 
index 81f701b8a43765047513b184b13b714f11ee30c4..5a228097602932a29452bef0fb19b029f6341591 100644 (file)
@@ -648,6 +648,12 @@ fastcall void do_int3(struct pt_regs *regs, long error_code)
 }
 #endif
 
+static inline void conditional_sti(struct pt_regs *regs)
+{
+       if ((uint8_t)(regs->xcs >> 16) == 0)
+               local_irq_enable();
+}
+
 /*
  * Our handling of the processor debug registers is non-trivial.
  * We do not clear them on entry and exit from the kernel. Therefore
@@ -680,11 +686,9 @@ fastcall void do_debug(struct pt_regs * regs, long error_code)
        if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
                                        SIGTRAP) == NOTIFY_STOP)
                return;
-#if 0
+
        /* It's safe to allow irq's after DR6 has been saved */
-       if (regs->eflags & X86_EFLAGS_IF)
-               local_irq_enable();
-#endif
+       conditional_sti(regs);
 
        /* Mask out spurious debug traps due to lazy DR7 setting */
        if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
@@ -967,15 +971,18 @@ void __init trap_init_f00f_bug(void)
 #endif
 
 
-/* NB. All these are "trap gates" (i.e. events_mask isn't cleared). */
+/*
+ * NB. All these are "trap gates" (i.e. events_mask isn't cleared) except
+ * for those that specify <dpl>|4 in the second field.
+ */
 static trap_info_t trap_table[] = {
        {  0, 0, __KERNEL_CS, (unsigned long)divide_error               },
-       {  1, 0, __KERNEL_CS, (unsigned long)debug                      },
-       {  3, 3, __KERNEL_CS, (unsigned long)int3                       },
+       {  1, 0|4, __KERNEL_CS, (unsigned long)debug                    },
+       {  3, 3|4, __KERNEL_CS, (unsigned long)int3                     },
        {  4, 3, __KERNEL_CS, (unsigned long)overflow                   },
        {  5, 3, __KERNEL_CS, (unsigned long)bounds                     },
        {  6, 0, __KERNEL_CS, (unsigned long)invalid_op                 },
-       {  7, 0, __KERNEL_CS, (unsigned long)device_not_available       },
+       {  7, 0|4, __KERNEL_CS, (unsigned long)device_not_available     },
        {  9, 0, __KERNEL_CS, (unsigned long)coprocessor_segment_overrun },
        { 10, 0, __KERNEL_CS, (unsigned long)invalid_TSS                },
        { 11, 0, __KERNEL_CS, (unsigned long)segment_not_present        },
index 44f902f50550a9db8d8743dac14d9e230077fce9..df278750fdc6be39e14044024a481dace0447f07 100644 (file)
@@ -1147,6 +1147,9 @@ asmlinkage void do_nmi(struct cpu_user_regs *regs, unsigned long reason)
 
 asmlinkage int math_state_restore(struct cpu_user_regs *regs)
 {
+    struct trap_bounce *tb;
+    trap_info_t *ti;
+
     /* Prevent recursion. */
     clts();
 
@@ -1154,10 +1157,15 @@ asmlinkage int math_state_restore(struct cpu_user_regs *regs)
 
     if ( current->arch.guest_context.ctrlreg[0] & X86_CR0_TS )
     {
-        struct trap_bounce *tb = &current->arch.trap_bounce;
+        tb = &current->arch.trap_bounce;
+        ti = &current->arch.guest_context.trap_ctxt[TRAP_no_device];
+
         tb->flags = TBF_EXCEPTION;
-        tb->cs    = current->arch.guest_context.trap_ctxt[7].cs;
-        tb->eip   = current->arch.guest_context.trap_ctxt[7].address;
+        tb->cs    = ti->cs;
+        tb->eip   = ti->address;
+        if ( TI_GET_IF(ti) )
+            tb->flags |= TBF_INTERRUPT;
+
         current->arch.guest_context.ctrlreg[0] &= ~X86_CR0_TS;
     }
 
@@ -1169,6 +1177,7 @@ asmlinkage int do_debug(struct cpu_user_regs *regs)
     unsigned long condition;
     struct vcpu *v = current;
     struct trap_bounce *tb = &v->arch.trap_bounce;
+    trap_info_t *ti;
 
     __asm__ __volatile__("mov %%db6,%0" : "=r" (condition));
 
@@ -1198,9 +1207,12 @@ asmlinkage int do_debug(struct cpu_user_regs *regs)
     /* Save debug status register where guest OS can peek at it */
     v->arch.guest_context.debugreg[6] = condition;
 
+    ti = &v->arch.guest_context.trap_ctxt[TRAP_debug];
     tb->flags = TBF_EXCEPTION;
-    tb->cs    = v->arch.guest_context.trap_ctxt[TRAP_debug].cs;
-    tb->eip   = v->arch.guest_context.trap_ctxt[TRAP_debug].address;
+    tb->cs    = ti->cs;
+    tb->eip   = ti->address;
+    if ( TI_GET_IF(ti) )
+        tb->flags |= TBF_INTERRUPT;
 
  out:
     return EXCRET_not_a_fault;